import 'dart:io';
import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:uuid/uuid.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';

import '../../models/download_task.dart';
import '../../models/virtual_file_node.dart';
import '../../models/file_metadata.dart';
import '../database_service.dart';
import '../tianyi_cloud_service.dart';
import '../notification_service.dart';
import '../preferences_service.dart';

class DownloadService extends GetxService {
  final DatabaseService _databaseService = Get.find<DatabaseService>();
  final TianyiCloudService _cloudService = Get.find<TianyiCloudService>();
  final NotificationService _notificationService = Get.find<NotificationService>();
  final PreferencesService _preferencesService = Get.find<PreferencesService>();
  
  late Dio _dio;
  
  // 下载任务列表
  final RxList<DownloadTask> _downloadTasks = <DownloadTask>[].obs;
  List<DownloadTask> get downloadTasks => _downloadTasks;
  
  // 正在下载的任务
  final RxList<DownloadTask> _activeDownloads = <DownloadTask>[].obs;
  List<DownloadTask> get activeDownloads => _activeDownloads;
  
  // 下载队列
  final List<DownloadTask> _downloadQueue = [];
  
  // 下载统计
  final RxInt _totalTasks = 0.obs;
  final RxInt _completedTasks = 0.obs;
  final RxInt _failedTasks = 0.obs;
  final RxDouble _totalProgress = 0.0.obs;
  
  int get totalTasks => _totalTasks.value;
  int get completedTasks => _completedTasks.value;
  int get failedTasks => _failedTasks.value;
  double get totalProgress => _totalProgress.value;
  
  // 取消令牌映射
  final Map<String, CancelToken> _cancelTokens = {};
  
  @override
  Future<void> onInit() async {
    super.onInit();
    _initDio();
    await _loadDownloadTasks();
    _startDownloadProcessor();
  }
  
  void _initDio() {
    _dio = Dio(BaseOptions(
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(minutes: 10),
    ));
  }
  
  // 加载下载任务
  Future<void> _loadDownloadTasks() async {
    final tasks = await _databaseService.getAllDownloadTasks();
    _downloadTasks.value = tasks;
    _updateStatistics();
    
    // 恢复未完成的下载任务
    final pendingTasks = tasks.where((task) => 
      task.status == DownloadStatus.pending || 
      task.status == DownloadStatus.paused
    ).toList();
    
    _downloadQueue.addAll(pendingTasks);
  }
  
  // 开始下载处理器
  void _startDownloadProcessor() {
    // 定期处理下载队列
    Stream.periodic(const Duration(seconds: 1)).listen((_) {
      _processDownloadQueue();
    });
  }
  
  // 处理下载队列
  Future<void> _processDownloadQueue() async {
    final maxConcurrent = _preferencesService.getMaxDownloadConcurrent();
    
    while (_activeDownloads.length < maxConcurrent && _downloadQueue.isNotEmpty) {
      final task = _downloadQueue.removeAt(0);
      await _startDownload(task);
    }
  }
  
  // 添加下载任务
  Future<DownloadTask> addDownloadTask(
    VirtualFileNode fileNode,
    FileMetadata fileMetadata, {
    String? customSavePath,
  }) async {
    // 获取下载URL
    final downloadUrl = await _cloudService.getDownloadUrl(fileMetadata.cloudId!);
    
    // 确定保存路径
    String savePath;
    if (customSavePath != null) {
      savePath = customSavePath;
    } else {
      final defaultPath = _preferencesService.getDefaultDownloadPath();
      if (defaultPath != null) {
        savePath = path.join(defaultPath, fileNode.name);
      } else {
        final documentsDir = await getApplicationDocumentsDirectory();
        final downloadDir = Directory(path.join(documentsDir.path, 'Downloads'));
        if (!await downloadDir.exists()) {
          await downloadDir.create(recursive: true);
        }
        savePath = path.join(downloadDir.path, fileNode.name);
      }
    }
    
    final task = DownloadTask(
      id: const Uuid().v4(),
      fileName: fileNode.name,
      cloudId: fileMetadata.cloudId!,
      downloadUrl: downloadUrl,
      savePath: savePath,
      fileSize: fileMetadata.fileSize,
      md5: fileMetadata.md5,
      createdTime: DateTime.now(),
    );
    
    await _databaseService.insertDownloadTask(task);
    _downloadTasks.add(task);
    _downloadQueue.add(task);
    _updateStatistics();
    
    return task;
  }
  
  // 批量添加下载任务
  Future<List<DownloadTask>> addMultipleDownloadTasks(
    List<VirtualFileNode> fileNodes,
    List<FileMetadata> fileMetadataList, {
    String? customSaveDir,
  }) async {
    final tasks = <DownloadTask>[];
    
    for (int i = 0; i < fileNodes.length; i++) {
      final fileNode = fileNodes[i];
      final metadata = fileMetadataList[i];
      
      String? savePath;
      if (customSaveDir != null) {
        savePath = path.join(customSaveDir, fileNode.name);
      }
      
      final task = await addDownloadTask(fileNode, metadata, customSavePath: savePath);
      tasks.add(task);
    }
    
    return tasks;
  }
  
  // 开始下载
  Future<void> _startDownload(DownloadTask task) async {
    try {
      // 创建取消令牌
      final cancelToken = CancelToken();
      _cancelTokens[task.id] = cancelToken;
      
      // 更新任务状态
      final updatedTask = task.copyWith(
        status: DownloadStatus.downloading,
        startTime: DateTime.now(),
      );
      await _updateTask(updatedTask);
      _activeDownloads.add(updatedTask);
      
      // 显示下载开始通知
      if (_preferencesService.getDownloadNotification()) {
        await _notificationService.showDownloadStartNotification(task.fileName);
      }
      
      // 确保保存目录存在
      final saveDir = Directory(path.dirname(task.savePath));
      if (!await saveDir.exists()) {
        await saveDir.create(recursive: true);
      }
      
      // 检查是否支持断点续传
      int startByte = 0;
      final tempFile = File('${task.savePath}.tmp');
      if (await tempFile.exists()) {
        startByte = await tempFile.length();
      }
      
      // 开始下载
      await _downloadFile(updatedTask, cancelToken, startByte);
      
    } catch (e) {
      if (e is DioException && e.type == DioExceptionType.cancel) {
        // 下载被取消
        await _handleDownloadCancelled(task);
      } else {
        await _handleDownloadError(task, e.toString());
      }
    } finally {
      _cancelTokens.remove(task.id);
    }
  }
  
  // 下载文件
  Future<void> _downloadFile(DownloadTask task, CancelToken cancelToken, int startByte) async {
    final tempFile = File('${task.savePath}.tmp');
    final finalFile = File(task.savePath);
    
    try {
      final response = await _dio.download(
        task.downloadUrl,
        tempFile.path,
        cancelToken: cancelToken,
        options: Options(
          headers: startByte > 0 ? {'Range': 'bytes=$startByte-'} : null,
        ),
        onReceiveProgress: (received, total) async {
          final totalReceived = startByte + received;
          final totalSize = startByte + total;
          final progress = (totalReceived / totalSize * 100).clamp(0.0, 100.0);
          
          final updatedTask = task.copyWith(
            downloadedBytes: totalReceived,
            progress: progress,
          );
          
          await _updateTask(updatedTask);
          
          // 更新进度通知
          if (_preferencesService.getDownloadNotification()) {
            await _notificationService.showDownloadProgressNotification(
              task.fileName,
              totalReceived,
              totalSize,
            );
          }
        },
      );
      
      if (response.statusCode == 200 || response.statusCode == 206) {
        // 验证文件完整性
        if (await _verifyFileIntegrity(tempFile, task.md5)) {
          // 移动临时文件到最终位置
          await tempFile.rename(finalFile.path);
          await _handleDownloadComplete(task);
        } else {
          throw Exception('文件校验失败');
        }
      } else {
        throw Exception('下载失败: HTTP ${response.statusCode}');
      }
      
    } catch (e) {
      rethrow;
    }
  }
  
  // 验证文件完整性
  Future<bool> _verifyFileIntegrity(File file, String expectedMd5) async {
    try {
      final actualMd5 = await TianyiCloudService.calculateFileMd5(file);
      return actualMd5.toLowerCase() == expectedMd5.toLowerCase();
    } catch (e) {
      return false;
    }
  }
  
  // 处理下载完成
  Future<void> _handleDownloadComplete(DownloadTask task) async {
    final completedTask = task.copyWith(
      status: DownloadStatus.completed,
      progress: 100.0,
      downloadedBytes: task.fileSize,
      completedTime: DateTime.now(),
    );
    
    await _updateTask(completedTask);
    _activeDownloads.removeWhere((t) => t.id == task.id);
    
    // 显示完成通知
    if (_preferencesService.getDownloadNotification()) {
      await _notificationService.showDownloadCompleteNotification(task.fileName);
    }
  }
  
  // 处理下载取消
  Future<void> _handleDownloadCancelled(DownloadTask task) async {
    final cancelledTask = task.copyWith(status: DownloadStatus.cancelled);
    await _updateTask(cancelledTask);
    _activeDownloads.removeWhere((t) => t.id == task.id);
  }
  
  // 处理下载错误
  Future<void> _handleDownloadError(DownloadTask task, String error) async {
    final failedTask = task.copyWith(
      status: DownloadStatus.failed,
      errorMessage: error,
    );
    
    await _updateTask(failedTask);
    _activeDownloads.removeWhere((t) => t.id == task.id);
    
    // 显示错误通知
    if (_preferencesService.getDownloadNotification()) {
      await _notificationService.showDownloadFailedNotification(task.fileName, error);
    }
  }
  
  // 暂停下载
  Future<void> pauseDownload(String taskId) async {
    final cancelToken = _cancelTokens[taskId];
    if (cancelToken != null) {
      cancelToken.cancel('用户暂停');
    }
    
    final task = _downloadTasks.firstWhereOrNull((t) => t.id == taskId);
    if (task != null && task.isDownloading) {
      final pausedTask = task.copyWith(status: DownloadStatus.paused);
      await _updateTask(pausedTask);
      _activeDownloads.removeWhere((t) => t.id == taskId);
    }
  }
  
  // 恢复下载
  Future<void> resumeDownload(String taskId) async {
    final task = _downloadTasks.firstWhereOrNull((t) => t.id == taskId);
    if (task != null && task.isPaused) {
      final resumedTask = task.copyWith(status: DownloadStatus.pending);
      await _updateTask(resumedTask);
      _downloadQueue.add(resumedTask);
    }
  }
  
  // 取消下载
  Future<void> cancelDownload(String taskId) async {
    final cancelToken = _cancelTokens[taskId];
    if (cancelToken != null) {
      cancelToken.cancel('用户取消');
    }
    
    final task = _downloadTasks.firstWhereOrNull((t) => t.id == taskId);
    if (task != null) {
      final cancelledTask = task.copyWith(status: DownloadStatus.cancelled);
      await _updateTask(cancelledTask);
      _activeDownloads.removeWhere((t) => t.id == taskId);
      _downloadQueue.removeWhere((t) => t.id == taskId);
      
      // 删除临时文件
      final tempFile = File('${task.savePath}.tmp');
      if (await tempFile.exists()) {
        await tempFile.delete();
      }
    }
  }
  
  // 删除下载任务
  Future<void> deleteDownloadTask(String taskId) async {
    final task = _downloadTasks.firstWhereOrNull((t) => t.id == taskId);
    if (task != null) {
      // 如果正在下载，先取消
      if (task.isDownloading) {
        await cancelDownload(taskId);
      }
      
      // 删除文件
      final file = File(task.savePath);
      if (await file.exists()) {
        await file.delete();
      }
      
      final tempFile = File('${task.savePath}.tmp');
      if (await tempFile.exists()) {
        await tempFile.delete();
      }
    }
    
    await _databaseService.deleteDownloadTask(taskId);
    _downloadTasks.removeWhere((t) => t.id == taskId);
    _activeDownloads.removeWhere((t) => t.id == taskId);
    _downloadQueue.removeWhere((t) => t.id == taskId);
    _updateStatistics();
  }
  
  // 清除已完成的任务
  Future<void> clearCompletedTasks() async {
    final completedTasks = _downloadTasks.where((t) => t.isCompleted).toList();
    for (final task in completedTasks) {
      await deleteDownloadTask(task.id);
    }
  }
  
  // 重试失败的任务
  Future<void> retryFailedTask(String taskId) async {
    final task = _downloadTasks.firstWhereOrNull((t) => t.id == taskId);
    if (task != null && task.isFailed) {
      final retryTask = task.copyWith(
        status: DownloadStatus.pending,
        errorMessage: null,
        downloadedBytes: 0,
        progress: 0.0,
        startTime: null,
        completedTime: null,
      );
      await _updateTask(retryTask);
      _downloadQueue.add(retryTask);
    }
  }
  
  // 更新任务
  Future<void> _updateTask(DownloadTask task) async {
    await _databaseService.updateDownloadTask(task);
    final index = _downloadTasks.indexWhere((t) => t.id == task.id);
    if (index != -1) {
      _downloadTasks[index] = task;
    }
    
    // 更新活跃下载列表
    final activeIndex = _activeDownloads.indexWhere((t) => t.id == task.id);
    if (activeIndex != -1) {
      _activeDownloads[activeIndex] = task;
    }
    
    _updateStatistics();
  }
  
  // 更新统计信息
  void _updateStatistics() {
    _totalTasks.value = _downloadTasks.length;
    _completedTasks.value = _downloadTasks.where((t) => t.isCompleted).length;
    _failedTasks.value = _downloadTasks.where((t) => t.isFailed).length;
    
    if (_downloadTasks.isNotEmpty) {
      final totalProgress = _downloadTasks.fold<double>(
        0.0,
        (sum, task) => sum + task.progress,
      );
      _totalProgress.value = totalProgress / _downloadTasks.length;
    } else {
      _totalProgress.value = 0.0;
    }
  }
  
  // 获取下载速度
  double getDownloadSpeed() {
    if (_activeDownloads.isEmpty) return 0.0;
    
    return _activeDownloads.fold<double>(
      0.0,
      (sum, task) => sum + task.downloadSpeed,
    );
  }
  
  // 获取剩余时间估算
  Duration? getEstimatedTimeRemaining() {
    final speed = getDownloadSpeed();
    if (speed <= 0) return null;
    
    final remainingBytes = _downloadTasks
        .where((t) => !t.isCompleted && !t.isFailed && !t.isCancelled)
        .fold<int>(0, (sum, task) => sum + (task.fileSize - task.downloadedBytes));
    
    if (remainingBytes <= 0) return null;
    
    final remainingSeconds = remainingBytes / speed;
    return Duration(seconds: remainingSeconds.round());
  }
  
  // 打开下载文件
  Future<void> openDownloadedFile(String taskId) async {
    final task = _downloadTasks.firstWhereOrNull((t) => t.id == taskId);
    if (task != null && task.isCompleted) {
      final file = File(task.savePath);
      if (await file.exists()) {
        // 这里可以集成文件打开功能
        // 例如使用 open_file 包
        print('打开文件: ${task.savePath}');
      }
    }
  }
}